package org.gpp.proj1.demo.map;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;

import org.gpp.proj1.logic.core.board.RobotPosition;
import org.gpp.proj1.map.GameMap;
import org.gpp.proj1.map.MalformedMapFileException;
import org.gpp.proj1.map.MapNode;
import org.gpp.proj1.map.parser.MapFileParser;
import org.gpp.proj1.map.renderer.MapNodeBuilder;

import com.jme.app.AbstractGame;
import com.jme.app.SimpleGame;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.FirstPersonHandler;
import com.jme.input.MouseInput;
import com.jme.intersection.BoundingPickResults;
import com.jme.intersection.PickResults;
import com.jme.math.Ray;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;

public class SelectionTilesDemo extends SimpleGame {
	
	// This will be my mouse
	AbsoluteMouse absoluteMouse;
	// The map node
	MapNode mapNode;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SelectionTilesDemo demo = new SelectionTilesDemo();
		demo.setDialogBehaviour(AbstractGame.ALWAYS_SHOW_PROPS_DIALOG);
		demo.start();
	}

	/**
	 * @see com.jme.app.BaseSimpleGame#simpleInitGame()
	 */
	@Override
	protected void simpleInitGame() {

		this.setCamera();
		
		this.createMap();
		this.createMouse();
		
		this.setMap();
		this.setMouse();
	}

	/**
	 * Configure camera position and light.
	 */
	private void setCamera() {
		// ambient light
		this.lightState.setGlobalAmbient( new ColorRGBA( 1.0f, 1.0f, 1.0f, 1.0f ) );
		// camera
		this.cam.setLocation(new Vector3f(50,180,450));
		this.cam.lookAt(new Vector3f(240,0,280), new Vector3f(0,1,0));
	}

	/**
	 * Configure map.
	 */
	private void setMap() {
		if (mapNode != null) {

			ColorRGBA alphaRed = new ColorRGBA(1.0f, 0.0f, 0.0f, 0.4f);
			mapNode.activateSelectionTiles(16, 8, 3, alphaRed, new LinkedList<RobotPosition>() );

			// Attach map to root node
			rootNode.attachChild(mapNode);
		}
	}

	/**
	 * Create a map node.
	 */
	private void createMap() {
		GameMap map = null;
		try {
			// parse map file
			map = MapFileParser.parseFile( "res/map/demoMap.map" );
		} catch (IOException e) {
			e.printStackTrace();
		} catch (MalformedMapFileException e) {
			e.printStackTrace();
		}
		
		if( map != null ) {
			// create node
			this.mapNode = MapNodeBuilder.buildNode( map );
		}		
	}

	/**
	 * Configure mouse interaction and behaviour.
	 */
	private void setMouse() {
		// Get the mouse input device and assign it to the AbsoluteMouse
		// Move the mouse to the middle of the screen to start with
		absoluteMouse.setLocalTranslation(new Vector3f(display.getWidth() / 2, display.getHeight() / 2, 0));
		// Assign the mouse to an input handler
        absoluteMouse.registerWithInputHandler( input );
        // stop Quake's "mouse look" effect (mouse doesn't move camera anymore)
		(( FirstPersonHandler ) input ).getMouseLookHandler().setEnabled( false );
		// Attach mouse to root node
		rootNode.attachChild(absoluteMouse);
	}

	/**
	 * Create mouse and set the cursor appearence.
	 */
	private void createMouse() {
		// Create a new mouse. Restrict its movements to the display screen.
		absoluteMouse = new AbsoluteMouse("Mouse", display.getWidth(), display.getHeight());

		// Get a picture for my mouse.
		TextureState ts = display.getRenderer().createTextureState();
        URL cursorLoc = null;
		try {
			cursorLoc = new File("res/images/cursor1.png").toURI().toURL();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
        Texture t = TextureManager.loadTexture(cursorLoc, Texture.MM_LINEAR, Texture.FM_LINEAR);
		ts.setTexture(t);
		absoluteMouse.setRenderState(ts);

		// Make the mouse's background blend with what's already there
		AlphaState as = display.getRenderer().createAlphaState();
		as.setBlendEnabled(true);
		as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
		as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
		as.setTestEnabled(true);
		as.setTestFunction(AlphaState.TF_GREATER);
		absoluteMouse.setRenderState(as);
	}
	
	/**
	 * @see com.jme.app.BaseSimpleGame#simpleUpdate()
	 */
	@Override
	protected void simpleUpdate() {
		// Get the mouse input device from the jME mouse
		// Is button 0 down? Button 0 is left click
		if (MouseInput.get().isButtonDown(0)) {

			Ray mouseRay = this.getMouseRay();
			this.checkPick( mouseRay );
		}
	}
	
	/**
	 * Obtains the Ray for the current mouse position.
	 * @return
	 */
	private Ray getMouseRay() {
		Vector2f screenPos = new Vector2f();
		// Get the position that the mouse is pointing to
		screenPos.set( absoluteMouse.getHotSpotPosition().x, absoluteMouse.getHotSpotPosition().y );
		// Get the world location of that X,Y value
		Vector3f nearWorldCoords = display.getWorldCoordinates(screenPos, 0);
		Vector3f farWorldCoords = display.getWorldCoordinates(screenPos, 1);
        // Create a ray starting from the camera, and going in the direction
		// of the mouse's location
		return new Ray( nearWorldCoords, farWorldCoords.subtractLocal( nearWorldCoords ).normalizeLocal());		
	}

	/**
	 * Check intersections between ray and scene elements and
	 * address solution in positive cases.
	 * @param mouseRay
	 */
	private void checkPick(Ray mouseRay) {
		// list for the intersected selection tiles
		PickResults pr = new BoundingPickResults();
		
		// test intersection of ray with selection tiles
		this.mapNode.getSelectionTiles().findPick(mouseRay, pr);
		
		// if list has elements, some tile was hit by the ray
		if (pr.getNumber() > 0) {
			// use the name of tile Quad to discover its position in map
			String selectedTile = pr.getPickData( 0 ).getTargetMesh().getParentGeom().getName();
			int[] coords = this.mapNode.getTilePositionInMap( selectedTile ); 
			
			// draw cursor tile
			this.mapNode.activateCursorTile(coords[0], coords[1], new ColorRGBA(0.0f, 1.0f, 0.0f, 0.4f));
		}
		else {
			// remove cursor tile
			this.mapNode.deactivateCursorTile();
		}
	}
}